<?php

/**
 * Description of elFinderVolumeFileSystemMappedMySQL
 * Extiende las funcionalidades de elFinderVolumeMySQL para adaptarlas al Generador
 * modificando aquellos métodos que acceden a la base de datos.
 * @todo Modificar los métodos de borrado y modificación de imagenes para que los borre/modifique de la tabla gen_multimedia_imagen
 * agregar los metodos de abm de videos / audio / documentos
 * refactor de los mime/types para guardarlos en una tabla
 * 
 * @author Diego
 */
class elFinderVolumeFileSystemMappedMySQL extends elFinderVolumeMySQL {

    /**
     * 
     * @deprecated Método para usar en un futuro cuando se quiera que las categórías salgan de la tabla gen_multimedia_categoria y no de la misma tabla donde se 
     * guardan los archivos
     * @param id $path
     */
    private function _getDirectories($path) {
        $sql = "SELECT 
                d.id, 
                d.id_padre as parent_id, 
                d.nombre as name, 
                d.read, 
                d.write, 
                d.locked, 
                d.hidden,
                IF(ch.id, 1, 0) AS dirs 
            FROM gen_multimedia_categoria AS d 
            LEFT JOIN gen_multimedia_categoria AS ch ON ch.id_padre = d.id 
            WHERE d.id_padre ='$path'
            GROUP BY d.id";

        $res = $this->query($sql);
        if ($res) {
            while ($row = $res->fetch_assoc()) {
                // debug($row);
                $id = $row['id'];
                if ($row['parent_id']) {
                    $row['phash'] = $this->encode($row['parent_id']);
                }
                $row["mime"] = "directory";
                unset($row['id']);
                unset($row['parent_id']);
                $stat = $this->updateCache($id, $row);

                if (($stat) && empty($stat['hidden'])) {
                    $this->dirsCache[$path][] = $id;
                }
            }
        }

//        echo "<pre> DIRECTORIES ";
//        print_r($this->dirsCache[$path]);
//        echo "</pre>";
    }

    /**
     * Cache dir contents
     *
     * @param  string  $path  dir path
     * @return void
     * @author Dmitry Levashov
     * */
    protected function cacheDir($path) {
        $this->dirsCache[$path] = array();
        $sql = 'SELECT 
                f.id, 
                f.parent_id, 
                f.name, 
                f.size, 
                f.mtime AS ts, 
                f.mime, 
                f.read, 
                f.write, 
                f.locked, 
                f.hidden, 
                f.width, 
                f.height, 
                IF(ch.id, 1, 0) AS dirs 
            FROM ' . $this->tbf . ' AS f 
            LEFT JOIN ' . $this->tbf . ' AS ch ON ch.parent_id=f.id AND ch.mime="directory"
            WHERE f.parent_id="' . $path . '"
            GROUP BY f.id';
        $res = $this->query($sql);
        if ($res) {
            while ($row = $res->fetch_assoc()) {
                // debug($row);
                $id = $row['id'];
                if ($row['parent_id']) {
                    $row['phash'] = $this->encode($row['parent_id']);
                }

                if ($row['mime'] == 'directory') {
                    unset($row['width']);
                    unset($row['height']);
                } else {
                    unset($row['dirs']);
                }

                unset($row['id']);
                unset($row['parent_id']);



                if (($stat = $this->updateCache($id, $row)) && empty($stat['hidden'])) {
                    $this->dirsCache[$path][] = $id;
                }
            }
        }
        return $this->dirsCache[$path];
    }

    /**
     * Sube fÃ­sicamente el archivo al fileSystem.
     * 
     * @param type $fp
     * @param type $dir
     * @param type $name
     * @param type $stat
     * @return boolean|string 
     * 
     * @todo hacer que el dir "../files" sea dinÃ¡mico. O bien se creen 4 dirs:
     *  - Imagenes,
     *  - videos
     *  - audios
     *  - documentos
     * Y luego se crean directorios por fechas para evitar que se colapse el fileSystem si crece 
     * mÃ¡s de 2gb.
     * 
     * @todo Revisar si no se puede simplificar este proceso dado que en _save tenemos una variable $tmpfile
     */
    private function _uploadPhysicallyFile($fp, $dir, $name, $stat) {
        $path = '../files' . DIRECTORY_SEPARATOR . $name;
        if (!($target = @fopen($path, 'wb'))) {
            return false;
        }

        while (!feof($fp)) {
            fwrite($target, fread($fp, 8192));
        }
        fclose($target);
        @chmod($path, $this->options['fileMode']);
        clearstatcache();
        return $path;
    }

    /**
     * Actualiza la tabla imagenes que contendrÃ­a la informaciÃ³n especÃ­fica de las imÃ¡genes
     * @param int $id
     * @param int $w
     * @param int $h
     * @param string $mime 
     */
    private function _updateImageTable($id, $w, $h, $mime) {
        $sql = "UPDATE gen_multimedia_imagen SET width = %d, height = %d, mime = '%s' WHERE id_multimedia = $id";
        $sql = sprintf($sql, $w, $h, $mime);
        $this->query($sql);
    }

    /**
     * Inserta una nueva fila en la tabla imÃ¡genes.
     * @param int $id
     * @param int $w
     * @param int $h
     * @param string $mime 
     */
    private function _insertImageTable($id, $w, $h, $mime) {
        $sql = "INSERT INTO gen_multimedia_imagen SET id_multimedia = %d, width = %d, height = %d, mime = '%s'";
        $sql = sprintf($sql, $id, $w, $h, $mime);
        $this->query($sql);
    }

    private function _saveImageInformation($lastFileInsertId, $id, $w, $h, $mime) {
        if ($id > 0) {
            $this->_updateImageTable($id, $w, $h, $mime);
        } else {
            $this->_insertImageTable($lastFileInsertId, $w, $h, $mime);
        }
    }

    /**
     * Create new file and write into it from file pointer.
     * Return new file path or false on error.
     *
     * @param  resource  $fp   file pointer
     * @param  string    $dir  target dir path
     * @param  string    $name file name
     * @param  array     $stat file stat (required by some virtual fs)
     * @return bool|string
     * @author Dmitry (dio) Levashov
     * */
    protected function _save($fp, $dir, $name, $stat) {
        $this->clearcache();
        $realPath = $this->_uploadPhysicallyFile($fp, $dir, $name, $stat);
        //file_put_contents('logFILEMYSQL.txt', $realPath);
        $mime = $stat['mime'];
        $w = !empty($stat['width']) ? $stat['width'] : 0;
        $h = !empty($stat['height']) ? $stat['height'] : 0;

        $id = $this->_joinPath($dir, $name);
        rewind($fp);
        $stat = fstat($fp);
        $size = $stat['size'];

        if (($tmpfile = tempnam($this->tmpPath, $this->id))) {
            if (($trgfp = fopen($tmpfile, 'wb')) == false) {
                unlink($tmpfile);
            } else {
                while (!feof($fp)) {
                    fwrite($trgfp, fread($fp, 8192));
                }
                fclose($trgfp);
                                //Cambiar el Replace por Update
                if ($id > 0) {
                    //$sql = 'REPLACE INTO %s (id, parent_id, name, size, mtime, mime, width, height, real_path) 
                    //VALUES (' . $id . ', %d, "%s", %d, %d, "%s", %d, %d, "%s")';
                    $sql = "UPDATE %s SET 
                            parent_id = %id,
                            name = '%s',
                            size = %d,
                            mtime = %d,
                            mime = '%s',
                            width = %d,
                            height = %d,
                            real_path = '%s' 
                            WHERE id = $id
                            ";
                } else {
                    //$sql = 'INSERT INTO %s (parent_id, name,  size, mtime, mime, width, height, real_path) VALUES (%d, "%s", %d, %d, "%s", %d, %d, "%s")';
                    $sql = "INSERT INTO %s SET 
                            parent_id = %d,
                            name = '%s',
                            size = %d,
                            mtime = %d,
                            mime = '%s',
                            width = %d,
                            height = %d,
                            real_path = '%s' 
                            ";
                }
                $sql = sprintf(
                        $sql, $this->tbf, $dir, $this->db->real_escape_string($name), $size, time(), $mime, $w, $h, addslashes($realPath)
                );
                $res = $this->query($sql);
                unlink($tmpfile);
                if ($res) {
                    $lastFileInsertId = $this->db->insert_id;
                    if (stripos($mime, 'image') !== false) {
                        $this->_saveImageInformation($lastFileInsertId, $id, $w, $h, $mime);
                    }
                    return $id > 0 ? $id : $lastFileInsertId;
                }
            }
        }

        $content = '';
        rewind($fp);
        while (!feof($fp)) {
            $content .= fread($fp, 8192);
        }

        $sql = $id > 0 ? 'REPLACE INTO %s (id, parent_id, name, content, size, mtime, mime, width, height) VALUES (' . $id . ', %d, "%s", "%s", %d, %d, "%s", %d, %d)' : 'INSERT INTO %s (parent_id, name, content, size, mtime, mime, width, height) VALUES (%d, "%s", "%s", %d, %d, "%s", %d, %d)';
        $sql = sprintf($sql, $this->tbf, $dir, $this->db->real_escape_string($name), $this->db->real_escape_string($content), $size, time(), $mime, $w, $h);

        unset($content);

        if ($this->query($sql)) {
            return $id > 0 ? $id : $this->db->insert_id;
        }

        return false;
    }

    /**
     * Get file contents
     *
     * @param  string  $path  file path
     * @return string|false
     * @author diego olmedo
     * */
    protected function _getContents($path) {
        $query = sprintf('SELECT real_path FROM %s WHERE id=%d', $this->tbf, $path);
        $res = $this->query($query);
        $r = $res->fetch_assoc();
        return $res && $r ? file_get_contents($r['real_path']) : false;
    }

    /*     * *************** file stat ******************* */

    /**
     * Return stat for given path.
     * Stat contains following fields:
     * - (int)    size    file size in b. required
     * - (int)    ts      file modification time in unix time. required
     * - (string) mime    mimetype. required for folders, others - optionally
     * - (bool)   read    read permissions. required
     * - (bool)   write   write permissions. required
     * - (bool)   locked  is object locked. optionally
     * - (bool)   hidden  is object hidden. optionally
     * - (string) alias   for symlinks - link target path relative to root path. optionally
     * - (string) target  for symlinks - link target path. optionally
     *
     * If file does not exists - returns empty array or false.
     *
     * @param  string  $path    file path 
     * @return array|false
     * @author Dmitry (dio) Levashov
     * */
    protected function _stat($path) {
        $sql = 'SELECT 
                        f.id, 
                        f.parent_id, 
                        f.name, 
                        f.size, 
                        f.mtime AS ts, 
                        f.mime, 
                        f.read, 
                        f.write, 
                        f.locked, 
                        f.hidden, 
                        f.width, 
                        f.height,
                        f.real_path,
                        IF(ch.id, 1, 0) AS dirs
                    FROM ' . $this->tbf . ' AS f 
                    LEFT JOIN ' . $this->tbf . ' AS p ON p.id = f.parent_id
                    LEFT JOIN ' . $this->tbf . ' AS ch ON ch.parent_id = f.id AND ch.mime = "directory"
                    WHERE f.id="' . $path . '"
                    GROUP BY f.id';

        $res = $this->query($sql);

        if ($res) {
            $stat = $res->fetch_assoc();
            if ($stat['parent_id']) {
                $stat['phash'] = $this->encode($stat['parent_id']);
            }
            if ($stat['mime'] == 'directory') {
                unset($stat['width']);
                unset($stat['height']);
            } else {
                unset($stat['dirs']);
            }
            unset($stat['id']);
            unset($stat['parent_id']);
            return $stat;
        }
        return array();
    }

    /**
     * Convert path related to root dir into real path
     *
     * @param  string  $path  file path
     * @return string
     * @author Dmitry (dio) Levashov
     * */
    protected function _abspath($path) {
        //return $path == DIRECTORY_SEPARATOR ? $this->root : $this->root.DIRECTORY_SEPARATOR.$path;
        return $path;
    }

    /**
     * Open file and return file pointer
     *
     * @param  string  $path  file path
     * @param  string  $mode  open file mode (ignored in this driver)
     * @return resource|false
     * @author Dmitry (dio) Levashov
     * */
    protected function _fopen($path, $mode = 'rb') {

        $fp = $this->tmbPath ? @fopen($this->tmpname($path), 'w+') : @tmpfile();


        if ($fp) {
            $query = 'SELECT real_path FROM ' . $this->tbf . ' WHERE id="' . $path . '"';
            if (($res = $this->query($query))
                    && ($r = $res->fetch_assoc())) {
                if (empty($r['real_path']))
                    return false;
                $fileContent = file_get_contents($r['real_path']);
                fwrite($fp, $fileContent);
                rewind($fp);
                return $fp;
            } else {
                $this->_fclose($fp, $path);
            }
        }

        return false;
    }

}

?>
